home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
coral
/
coral.c
next >
Wrap
C/C++ Source or Header
|
1995-05-03
|
21KB
|
690 lines
/*
* @(#) coral.c 1.3 93/11/02 MRINC
*
* Written using CGI 10 Jun 1987 by Ron Record (rr@sco.com)
* Rewritten using X11 06 Apr 1993 by Ron Record (rr@sco.com)
*/
/*************************************************************************
* *
* Copyright (c) 1987-1993 Ronald Joe Record *
* *
* All rights reserved. No part of this program or publication may be *
* reproduced, transmitted, transcribed, stored in a retrieval system, *
* or translated into any language or computer language, in any form or *
* by any means, electronic, mechanical, magnetic, optical, chemical, *
* biological, or otherwise, without the prior written permission of: *
* *
* Ronald Joe Record (408) 458-3718 *
* 212 Owen St., Santa Cruz, California 95062 USA *
* *
*************************************************************************/
#include "coral.h"
int col_duration = 0;
int now_x, now_y, max_y;
int width, height;
int nballs = 16;
int coral_hue, count;
int nummaps=1, delay=0;
int demo=0, useroot=0, full=0, oflag=0, spin=0;
int maxcolor, next;
int **xy;
char *outname;
extern long lrand48();
extern void BufferPoint(), InitBuffer(), FlushBuffer();
void
usage()
{
printf("Usage: coral [-o file][-dsuFRTV]");
printf("[-m #][-w width][-h height]\n");
printf("\t-d indicates demo mode\n");
printf("\t-s indicates spin color wheel when done computing\n");
printf("\t-R indicates use the root window\n");
printf("\t-m # indicates a minimum color index of # (0-255)\n");
printf("\t-o file will save the output as 'file' in PPM format\n");
printf("\t-w # indicates a window width of #\n");
printf("\t-h # indicates a window height of #\n");
printf("\t-u produces this message\n");
printf("During display :\n");
printf("\t'f' or 'F' will save the picture as a PPM file\n");
printf("\t'+' will increment and '-' decrement the minimum color index\n");
printf("\t'r' or 's' will spin the color wheel forwards or backwards\n");
printf("\t'W' will increment and 'w' decrement the color map selection\n");
printf("\t'?' or 'h' will display the usage message\n");
printf("\t'q' or 'Q' will quit\n");
}
void
init_contexts()
{
static int i;
/*
* create default, writable, graphics contexts for the canvas.
*/
Data_GC[0] = XCreateGC(dpy, DefaultRootWindow(dpy),
(unsigned long) NULL, (XGCValues *) NULL);
/* set the background to black */
XSetBackground(dpy,Data_GC[0],BlackPixel(dpy, screen));
/* set the foreground of the 0th context to black */
XSetForeground(dpy, Data_GC[0], BlackPixel(dpy, screen));
Data_GC[1] = XCreateGC(dpy, DefaultRootWindow(dpy),
(unsigned long) NULL, (XGCValues *) NULL);
/* set the background to black */
XSetBackground(dpy,Data_GC[1],BlackPixel(dpy, screen));
/* set the foreground of the 1st context to white */
XSetForeground(dpy, Data_GC[1], WhitePixel(dpy, screen));
for (i=2; i<maxcolor; i++) {
Data_GC[i] = XCreateGC(dpy, DefaultRootWindow(dpy),
(unsigned long) NULL, (XGCValues *) NULL);
/* set the background to black */
XSetBackground(dpy,Data_GC[i],BlackPixel(dpy, screen));
/* set the foreground of the ith context to i */
XSetForeground(dpy, Data_GC[i], i);
}
}
void
Clear()
{
XFillRectangle(dpy, pixmap, Data_GC[0], 0, 0, width, height);
XCopyArea(dpy, pixmap, canvas, Data_GC[0], 0, 0, width, height, 0, 0);
}
void
freemem()
{
static int i;
for (i=0;i<=width;i++)
free(xy[i]);
free(xy);
}
void
setupmem()
{
static int i;
if ((xy=(int **)malloc((width+1)*sizeof(int *))) == (int **)NULL) {
printf("Error malloc'ing xy.\n");
exit (-1);
}
for (i=0;i<width+1;i++) {
if ((xy[i]=(int *)malloc(height*sizeof(int)))==(int *)NULL){
printf("Error malloc'ing xy[%d].\n", i);
exit (-1);
}
}
}
void
init_pts()
{
static int i, j;
static int initial_x, initial_y;
for (i=0; i<width+1; i++)
for (j=0; j<height; j++)
xy[i][j] = 0;
max_y = 2;
initial_y = 0;
for (j=0;j<nballs;j++) {
initial_x = ((int)lrand48() % (width-2)) + 1;
xy[initial_x][initial_y] = coral_hue;
BufferPoint(dpy, canvas, pixmap, Data_GC, &Points, coral_hue,
initial_x, height - initial_y - 1);
}
FlushBuffer(dpy,canvas,pixmap,Data_GC,&Points,coral_hue,coral_hue+1);
count = nballs;
}
#define x_str 10
void
print_help()
{
static char str[80];
static int y_str, spacing;
static int ascent, descent, dir;
static XCharStruct overall;
static GC gc;
gc = Data_GC[1];
XClearWindow(dpy, help);
y_str = 60;
sprintf(str,"During run-time, interactive control can be exerted via : ");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
XQueryTextExtents(dpy,(XID)XGContextFromGC(gc),"Hey!",
4,&dir,&ascent,&descent,&overall);
spacing = ascent + descent + 5;
y_str += 2 * spacing;
sprintf(str," - lowers the value of mincolindex, + raises it");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," f or F saves coral to a PPM file");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," h or H or ? displays this message");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," n goes on to the next coral");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," N creates a new replacement coral");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," r or s spins the colorwheel");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," w decrements, W increments the color wheel index");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += spacing;
sprintf(str," q or Q exits");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
y_str += 2*spacing;
sprintf(str,"Press 'h', 'H', or '?' to unmap the help window");
XDrawImageString(dpy,help,gc,x_str,y_str,str,strlen(str));
}
void
redisplay (event)
XExposeEvent *event;
{
if ((event->window == help) && (!useroot))
print_help();
else {
/*
* Extract the exposed area from the event and copy
* from the saved pixmap to the window.
*/
XCopyArea(dpy, pixmap, canvas, Data_GC[0], event->x, event->y,
event->width, event->height, event->x, event->y);
}
}
void
resize()
{
Window r;
int j;
int x, y;
unsigned int bw, d, new_w, new_h;
extern void Clear(), midpoint(), event_loop();
freemem();
XGetGeometry(dpy,canvas,&r,&x,&y,&new_w,&new_h,&bw,&d);
if (((int)new_w == width) && ((int)new_h == height)) {
setupmem();
InitBuffer(&Points, maxcolor);
Clear();
init_pts();
return;
}
width = (int)new_w; height = (int)new_h;
if (pixmap)
XFreePixmap(dpy, pixmap);
pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy),
width, height, DefaultDepth(dpy, screen));
setupmem();
InitBuffer(&Points, maxcolor);
Clear();
init_pts();
FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 0, maxcolor);
}
void
Cleanup() {
freemem();
XCloseDisplay(dpy);
}
/* Store coral growth in PPM format */
void
save()
{
FILE *outfile;
unsigned char c;
XImage *ximage;
static int i,j;
struct Colormap {
unsigned char red;
unsigned char green;
unsigned char blue;
};
struct Colormap *colormap=NULL;
if ((colormap=
(struct Colormap *)malloc(sizeof(struct Colormap)*maxcolor))
== NULL) {
fprintf(stderr,"Error malloc'ing colormap array\n");
Cleanup();
exit(-1);
}
outfile = fopen(outname,"w");
if(!outfile) {
perror(outname);
Cleanup();
exit(-1);
}
ximage=XGetImage(dpy, pixmap, 0, 0, width, height, AllPlanes, ZPixmap);
for (i=0;i<maxcolor;i++) {
colormap[i].red=(unsigned char)(Colors[i].red >> 8);
colormap[i].green=(unsigned char)(Colors[i].green >> 8);
colormap[i].blue =(unsigned char)(Colors[i].blue >> 8);
}
fprintf(outfile,"P%d %d %d\n",6,width,height);
fprintf(outfile,"%d\n",maxcolor-1);
for (j=0;j<height;j++)
for (i=0;i<width;i++) {
c = (unsigned char)XGetPixel(ximage,i,j);
fwrite((char *)&colormap[c],sizeof colormap[0],1,outfile);
}
fclose(outfile);
free(colormap);
}
void
Redraw() {
static int i, j;
extern void event_loop();
FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 0, maxcolor);
Clear();
for (i=0; i < width; i++)
for (j=0; j < height; j++)
if (xy[i][j])
BufferPoint(dpy, canvas, pixmap, Data_GC, &Points, xy[i][j],
i, height - j - 1);
FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 0, maxcolor);
}
void
Getkey(event)
XKeyEvent *event;
{
char key;
static int spinning=0, spindir=0;
static XWindowAttributes attr;
extern void init_color(), write_cmap();
if (XLookupString(event, (char *)&key, sizeof(key), (KeySym *)0,
(XComposeStatus *) 0) > 0)
switch (key) {
case '\015': /*write out current colormap to $HOME/.<prog>map*/
write_cmap(dpy,cmap,Colors,maxcolor,"coral","Coral");
break;
case '+': mincolindex += INDEXINC;
if (mincolindex > maxcolor)
mincolindex = 1;
init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
mincolindex,maxcolor,numwheels,"coral","Coral",0);
break;
case '-': mincolindex -= INDEXINC;
if (mincolindex < 1)
mincolindex = maxcolor - 1;
init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
mincolindex,maxcolor,numwheels,"coral","Coral",0);
break;
case 'd': delay -= 25; if (delay < 0) delay = 0; break;
case 'D': delay += 25; break;
case 'f': /* save in PPM format file */
case 'F': save(); break;
case 'n': /* go on to the next coral */
next = 1;
break;
case 'N': /* go on to the next coral */
nummaps++; /* but don't increment the coral counter */
next = 1;
break;
case 'S':
case 'R': spinning=0;
break;
case 'r': spinning=1; spindir=1;
Spin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, 1);
break;
case 's': spinning=1; spindir=0;
Spin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, 0);
break;
case '\027': /* (ctrl-W) read palette from $HOME/.coralmap */
numwheels = 0;
init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
mincolindex,maxcolor,numwheels,"coral","Coral",0);
break;
case 'W':
if (numwheels < MAXWHEELS)
numwheels++;
else
numwheels = 0;
init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
mincolindex,maxcolor,numwheels,"coral","Coral",0);
break;
case 'w':
if (numwheels > 0)
numwheels--;
else
numwheels = MAXWHEELS;
init_color(dpy,canvas,cmap,Colors,STARTCOLOR,
mincolindex,maxcolor,numwheels,"coral","Coral",0);
break;
case '?':
case 'h':
if (!useroot) {
XGetWindowAttributes(dpy, help, &attr);
if (attr.map_state != IsUnmapped)
XUnmapWindow(dpy, help);
else {
XMapRaised(dpy, help);
print_help();
}
}
break;
case 'X': /* restart coral growth with new seeds */
FlushBuffer(dpy,canvas,pixmap,Data_GC,&Points,0,maxcolor);
InitBuffer(&Points, maxcolor);
Clear();
init_pts();
break;
case 'Q':
case 'q': Cleanup(); exit(0); break;
}
if (spinning)
Spin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, spindir);
}
void
parseargs(argc, argv)
int argc;
char *argv[];
{
int c;
extern int optind, getopt();
extern double atof();
extern char *optarg;
outname = "coral.ppm";
width = 512; height = 480;
while((c = getopt(argc, argv, "dsuFRTVc:h:k:m:n:o:w:D:N:")) != EOF)
{ switch(c)
{
case 'c':
numwheels = atoi(optarg);
if (numwheels > MAXWHEELS)
numwheels = MAXWHEELS;
if (numwheels < 0)
numwheels = 0;
break;
case 'd':
demo++;
break;
case 'u':
usage();
exit(0);
case 'h':
height = atoi(optarg);
break;
case 'k':
col_duration = atoi(optarg);
break;
case 'm':
mincolindex = atoi(optarg);
break;
case 'n':
nummaps = atoi(optarg);
break;
case 'o':
++oflag;
outname = optarg;
break;
case 's':
++spin;
break;
case 'w':
width = atoi(optarg);
break;
case 'D':
delay = atoi(optarg);
break;
case 'F':
full++;
break;
case 'N':
nballs = atoi(optarg);
break;
case 'R':
useroot++;
break;
case '?':
usage();
exit(1);
break;
}
}
}
void
event_loop()
{
int n;
XEvent event;
n = XEventsQueued(dpy, QueuedAfterFlush);
while (n--) {
XNextEvent(dpy, &event);
switch(event.type) {
case KeyPress:
Getkey(&event);
break;
case Expose:
redisplay(&event);
break;
case ConfigureNotify:
resize();
break;
}
}
}
int
checkit()
{
static int i, j;
for (i=0;i<3;i++)
for (j=0;j<3;j++)
if (xy[now_x + i - 1][now_y + j - 1])
return(0);
return(1);
}
int
walk(x,y)
int x,y;
{
now_x = x;
now_y = y;
if (checkit() == 0)
return(1);
for(;;) {
event_loop();
now_x += (((int)lrand48()%3) - 1);
now_y--;
if ((now_y <= 0) || (now_x >= width) || (now_x <= 0))
return(0);
if (checkit() == 0)
return(1);
}
return(0);
}
aggregate()
{
static int enter_x, enter_y;
enter_x = ((int)lrand48() % (width-2)) + 1;
enter_y = (max_y > (height - 1)) ? (height - 1) : max_y;
if (walk(enter_x,enter_y)) {
count++;
max_y = (now_y > (max_y - 2)) ? now_y + 2 : max_y;
if ((count%col_duration) == 0) {
FlushBuffer(dpy,canvas,pixmap,Data_GC,&Points,coral_hue,coral_hue+1);
count=1;
coral_hue++;
if (coral_hue >= maxcolor)
coral_hue = STARTCOLOR;
}
xy[now_x][now_y] = coral_hue;
BufferPoint(dpy, canvas, pixmap, Data_GC, &Points, coral_hue,
now_x, height - now_y - 1);
FlushBuffer(dpy,canvas,pixmap,Data_GC,&Points,coral_hue,coral_hue+1);
}
}
main(argc,argv)
int argc;
char *argv[];
{
static int i, j;
XSizeHints hint;
Atom __SWM_VROOT = None;
Window rootReturn, parentReturn, *children;
unsigned int numChildren;
extern void srand48(), init_color();
parseargs(argc,argv);
dpy = XOpenDisplay("");
screen = DefaultScreen(dpy);
if (full || useroot) {
width = XDisplayWidth(dpy, screen);
height = XDisplayHeight(dpy, screen);
}
maxcolor = (int)XDisplayCells(dpy, screen);
if (maxcolor <= 16) {
STARTCOLOR = 2; delay = 100;
INDEXINC = 1; mincolindex = 5;
}
maxcolor = Min(maxcolor, MAXCOLOR);
if (col_duration == 0)
col_duration = Min(nballs * maxcolor, 4096);
coral_hue = STARTCOLOR;
/*
* Create the pixmap to hold the coral growth
*/
pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), width, height,
DefaultDepth(dpy, screen));
/*
* Create the window to display the fractal topographic map
*/
hint.x = 0;
hint.y = 0;
hint.width = width;
hint.height = height;
hint.flags = PPosition | PSize;
if (useroot) {
canvas = DefaultRootWindow(dpy);
/* search for virtual root (from ssetroot by Tom LaStrange) */
__SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False);
XQueryTree(dpy,canvas,&rootReturn,&parentReturn,&children,&numChildren);
for (j = 0; j < numChildren; j++) {
Atom actual_type;
int actual_format;
long nitems, bytesafter;
Window *newRoot = NULL;
if (XGetWindowProperty (dpy, children[j], __SWM_VROOT,0,1, False,
XA_WINDOW, &actual_type, &actual_format, &nitems, &bytesafter,
(unsigned char **) &newRoot) == Success && newRoot) {
canvas = *newRoot;
break;
}
}
}
else {
canvas = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
0, 0, width, height, 5, 0, 1);
XSetStandardProperties(dpy, canvas, "Coral by Ron Record",
"Coral", None, argv, argc, &hint);
XMapRaised(dpy, canvas);
XSelectInput(dpy,canvas,KeyPressMask|ExposureMask|StructureNotifyMask);
}
XChangeProperty(dpy, canvas, XA_WM_CLASS, XA_STRING, 8, PropModeReplace,
"coral", strlen("coral"));
/*
* Create the window used to display the help info
*/
if (!useroot) {
hint.x = XDisplayWidth(dpy, screen) / 4;
hint.y = XDisplayHeight(dpy, screen) / 4;
hint.width = hint.x * 2;
hint.height = hint.y * 2;
help = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
hint.x, hint.y, hint.width, hint.height, 5, 0, 1);
XSetWindowBackground(dpy, help, BlackPixel(dpy, screen));
/* Title */
XSetStandardProperties(dpy,help,"Help","Help",None,argv,argc,&hint);
XSelectInput(dpy,help,KeyPressMask|ExposureMask);
/* Try to write into a new color map */
cmap = XCreateColormap(dpy,canvas,DefaultVisual(dpy,screen),AllocAll);
init_color(dpy, canvas, cmap, Colors, STARTCOLOR, mincolindex, maxcolor,
numwheels,"coral", "Coral", 0);
/* install new color map */
XSetWindowColormap(dpy, canvas, cmap);
XSetWindowColormap(dpy, help, cmap);
}
init_contexts();
setupmem();
Clear();
srand48((long)time(0));
for (i=0; i!=nummaps; i++) {
next = 0;
InitBuffer(&Points, maxcolor);
init_pts();
for (;;) {
event_loop();
aggregate();
if (now_y >= (height - 1))
break;
}
FlushBuffer(dpy, canvas, pixmap, Data_GC, &Points, 0, maxcolor);
if (oflag)
save();
if (demo) {
event_loop();
DemoSpin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, 4);
event_loop();
for (j=0; j<=MAXWHEELS; j++) {
init_color(dpy, canvas, cmap, Colors, STARTCOLOR, mincolindex,
maxcolor, i, "coral", "Coral", 0);
event_loop();
sleep(1);
}
}
else if (useroot) {
XSetWindowBackgroundPixmap(dpy, canvas, pixmap);
XFreePixmap(dpy, pixmap);
XClearWindow(dpy, canvas);
XFlush(dpy);
Cleanup();
exit(0);
}
else {
XSync(dpy, True);
if (spin)
Spin(dpy, cmap, Colors, STARTCOLOR, maxcolor, delay, 0);
for (;;) {
event_loop();
if (next) break;
}
}
}
Cleanup();
exit(0);
}